package org.bulu.project.system.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import org.bulu.project.common.constant.JwtClaimConstants;
import org.bulu.project.system.security.SysUserDetails;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * JWT Token 工具类
 *
 * @author Ray Hao
 * @since 2.6.0
 */
@Component
public class JwtUtils {

    /**
     * JWT 加解密使用的密钥
     */
    private static byte[] key;


    /**
     * JWT Token 的有效时间(单位:秒)
     */
    private static int ttl;


    @Value("${security.jwt.key}")
    public void setKey(String key) {
        JwtUtils.key = key.getBytes();
    }

    @Value("${security.jwt.ttl}")
    public void setTtl(Integer ttl) {
        JwtUtils.ttl = ttl;
    }

    /**
     * 生成 JWT Token
     *
     * @param authentication 用户认证信息
     * @return Token 字符串
     */
    public static String createToken(Authentication authentication) {

        // 从认证信息中获取用户详细信息，将其转换为SysUserDetails类型
        SysUserDetails userDetails = (SysUserDetails) authentication.getPrincipal();

        // 创建一个Map来存储JWT的payload（载荷），即JWT中携带的数据
        Map<String, Object> payload = new HashMap<>();
        // 将用户ID添加到payload中
        payload.put(JwtClaimConstants.USER_ID, userDetails.getUserId()); // 存储用户ID
        // 将部门ID添加到payload中
        payload.put(JwtClaimConstants.DEPT_ID, userDetails.getDeptId()); // 存储部门ID
        // 将数据权限范围添加到payload中
        payload.put(JwtClaimConstants.DATA_SCOPE, userDetails.getDataScope()); // 存储数据权限范围

        // 从用户详细信息中获取角色信息，使用Java 8的流API进行转换和收集
        // 将角色信息添加到payload中
        Set<String> roles = userDetails.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority) // 获取角色的权限字符串
                .collect(Collectors.toSet()); // 转换为Set集合
        payload.put(JwtClaimConstants.AUTHORITIES, roles); // 存储角色信息

        // 获取当前日期和时间
        Date now = new Date();
        // 计算JWT的过期时间，基于当前时间和预设的有效期（ttl秒）
        Date expiration = DateUtil.offsetSecond(now, ttl);
        // 将签发时间添加到payload中
        payload.put(JWTPayload.ISSUED_AT, now); // 存储签发时间
        // 将过期时间添加到payload中
        payload.put(JWTPayload.EXPIRES_AT, expiration); // 存储过期时间
        // 将用户名称添加到payload中
        payload.put(JWTPayload.SUBJECT, authentication.getName()); // 存储主题，通常是用户名
        // 生成JWT的唯一标识符，并添加到payload中
        payload.put(JWTPayload.JWT_ID, IdUtil.simpleUUID()); // 存储JWT ID

        // 使用JWTUtil工具类和提供的payload及密钥key来创建JWT
        // 返回创建的JWT
        return JWTUtil.createToken(payload, key);
    }


    /**
     * 从 JWT Token 中解析 Authentication  用户认证信息
     *
     * @param payloads JWT 载体
     * @return 用户认证信息
     */
    public static UsernamePasswordAuthenticationToken getAuthentication(JSONObject payloads) {
        SysUserDetails userDetails = new SysUserDetails();
        userDetails.setUserId(payloads.getLong(JwtClaimConstants.USER_ID)); // 用户ID
        userDetails.setDeptId(payloads.getLong(JwtClaimConstants.DEPT_ID)); // 部门ID
        userDetails.setDataScope(payloads.getInt(JwtClaimConstants.DATA_SCOPE)); // 数据权限范围

        userDetails.setUsername(payloads.getStr(JWTPayload.SUBJECT)); // 用户名
        // 角色集合
        Set<SimpleGrantedAuthority> authorities = payloads.getJSONArray(JwtClaimConstants.AUTHORITIES)
                .stream()
                .map(authority -> new SimpleGrantedAuthority(Convert.toStr(authority)))
                .collect(Collectors.toSet());

        return new UsernamePasswordAuthenticationToken(userDetails, "", authorities);
    }


}
